﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PzemSimulate
{
    public partial class MainForm : Form
    {


        SerialPort serialPort = new SerialPort();

        public MainForm()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cmbPorts.DataSource = SerialPort.GetPortNames();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (!serialPort.IsOpen)
            {
                serialPort.PortName = cmbPorts.SelectedItem.ToString();
                serialPort.BaudRate = 9600;
                serialPort.DataBits = 8;
                serialPort.Parity = Parity.None;
                serialPort.StopBits = StopBits.One;
                serialPort.Open();
                serialPort.DataReceived += SerialPort_DataReceived;
                if (serialPort.IsOpen)
                {
                    btnStart.Text = "关闭";
                }
            }
            else
            {
                serialPort.Close();
                if (!serialPort.IsOpen)
                {
                    btnStart.Text = "打开";
                }
            }
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(100); // 等待数据接收完成
            //int bytes = serialPort.BytesToRead;
            byte[] buffer = new byte[8];
            serialPort.Read(buffer, 0, 8);

            for(int i = 0; i < buffer.Length; i++)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("{0:X2} ", buffer[i]);
                sb.Append(" ");
            }

            Log(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " request: " + BitConverter.ToString(buffer).Replace("-"," "));


            // 校验CRC
            if (!ValidateCRC(buffer))
            {
                Log("Invalid CRC");
                return;
            }

            // 解析请求
            byte address = buffer[0];
            byte functionCode = buffer[1];

            if (functionCode == 0x04) // 读输入寄存器
            {
                ushort startAddr = (ushort)((buffer[2] << 8) | buffer[3]);
                ushort regCount = (ushort)((buffer[4] << 8) | buffer[5]);
                HandleReadRegisters(address, startAddr, regCount);
            }
        }
        private bool ValidateCRC(byte[] data)
        {
            // 检查数据长度是否足够包含CRC（至少2字节）
            if (data.Length < 2) return false;

            // 获取数据部分（排除最后两个CRC字节）
            byte[] dataWithoutCRC = new byte[data.Length - 2];
            Array.Copy(data, 0, dataWithoutCRC, 0, dataWithoutCRC.Length);

            // 计算数据的CRC
            byte[] calculatedCRC = CalculateCRC(dataWithoutCRC);

            // 比较计算出的CRC与接收到的CRC
            // 注意Modbus CRC是小端模式（低字节在前）
            return data[data.Length - 2] == calculatedCRC[0]
                && data[data.Length - 1] == calculatedCRC[1];
        }

        private void HandleReadRegisters(byte address, ushort startAddr, ushort regCount)
        {
            List<byte> response = new List<byte>();
            response.Add(address);
            response.Add(0x04); // 功能码
            response.Add((byte)(regCount * 2)); // 字节数

            //电压值
            try
            {
                var voltage = ushort.Parse(txtVoltage.Text);
                response.Add((byte)(voltage >> 8));
                response.Add((byte)(voltage & 0xFF));

            }
            catch (FormatException)
            {

            }

            //电流
            try
            {
                var current = uint.Parse(txtCurrent.Text);

                response.Add((byte)(current >> 8));
                response.Add((byte)(current & 0xFF));
                response.Add((byte)(current >> 24));
                response.Add((byte)(current >> 16));
            }
            catch (FormatException)
            {
            }
         
          
           

            // 功率
            try
            {
                var power = uint.Parse(txtPower.Text);
                response.Add((byte)(power >> 8));
                response.Add((byte)(power & 0xFF));
                response.Add((byte)(power >> 24));
                response.Add((byte)(power >> 16));
            }
            catch(FormatException)
            {

            }
           
           

            // 电能
            try
            {
                var energy = uint.Parse(txtEnergy.Text);
                response.Add((byte)(energy >> 8));
                response.Add((byte)(energy & 0xFF));
                response.Add((byte)(energy >> 24));
                response.Add((byte)(energy >> 16));
            }
            catch(FormatException)
            {

            }
           
          

            // 频率
            try
            {
                var frequency = ushort.Parse(txtFrequency.Text);
                response.Add((byte)(frequency >> 8));
                response.Add((byte)(frequency & 0xFF));
            }
            catch(FormatException)
            {

            }
            

            //功率因数
            try
            {
                var pf = ushort.Parse(txtPF.Text);
                response.Add((byte)(pf >> 8));
                response.Add((byte)(pf & 0xFF));
            }
            catch (FormatException)
            {

            }
          

            //报警
            try
            {
                response.Add(0x00);
                response.Add(0x00);
            }
            catch(Exception)
            {

            }
          


            // 添加CRC
            byte[] crc = CalculateCRC(response.ToArray());
            response.AddRange(crc);
            Log(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " response: " + BitConverter.ToString(response.ToArray()).Replace("-", " "));
            serialPort.Write(response.ToArray(), 0, response.Count);
        }

        private byte[] CalculateCRC(byte[] data)
        {
            ushort crc = 0xFFFF;
            for (int pos = 0; pos < data.Length; pos++)
            {
                crc ^= data[pos];
                for (int i = 8; i != 0; i--)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            return BitConverter.GetBytes(crc);
        }

        private void Log(string message)
        {
            this.Invoke((MethodInvoker)delegate
            {
                txtLog.AppendText(message + "\r\n");
                txtLog.SelectionStart = txtLog.Text.Length;
                txtLog.ScrollToCaret();
            });
            //txtLog.AppendText(message + "\r\n");
            //txtLog.SelectionStart = txtLog.Text.Length;
            //txtLog.ScrollToCaret();
        }
    }
}
